#!/bin/sh
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
#

. /lib/svc/share/smf_include.sh
. /lib/svc/share/net_include.sh

IPADM=/sbin/ipadm
SVCCFG=/usr/sbin/svccfg
SVCPROP=/usr/bin/svcprop
SVCADM=/usr/sbin/svcadm
ROUTE=/sbin/route

NET_NWAM_FMRI="svc:/network/physical:nwam"
NET_INSTALL_FMRI=$SMF_FMRI

NET_V4IF=install_ipv4_interface
NET_V6IF=install_ipv6_interface

NET_UNDEFINED_STRING_PROP="\"\""

net_install_debug=0

unset net_install_name net_install_addrtype net_install_addr \
    net_install_dhcpwait net_install_interface_id \
    net_install_stateless net_install_stateful net_install_route

net_configure_install_if()
{
	ipv6_interface=$1

	case $net_install_addrtype in
	static)
		cmd="$IPADM create-addr -T static "
		cmd=$cmd"-a local=$net_install_addr $net_install_name"
		;;

	dhcp)
		dhcpwait=""
		if [ "$net_install_dhcpwait" != "" ]; then
			dhcpwait="-w $net_install_dhcpwait"
		fi

		cmd="$IPADM create-addr -T dhcp $dhcpwait $net_install_name"
		;;
	addrconf)
		interface_id=""
		if [ "$net_install_interface_id" != "" ]; then
			interface_id="-i $net_install_interface_id"
		fi

		state=""
		if [ "$net_install_stateless" != "" ]; then
			state="-p stateless=$net_install_stateless"
		fi

		if [ "$net_install_stateful" != "" ]; then
			if [ "$state" = "" ]; then
				state="-p stateful=$net_install_stateful"
			else
				state=$state",stateful=$net_install_stateful"
			fi
		fi

		cmd="$IPADM create-addr -T addrconf "
		cmd=$cmd"$interface_id $state $net_install_name"
		;;
	esac

	$cmd
	if [ $? -ne 0 ]; then
		net_record_err "Error configuring interface:\n\"$cmd\"" $?
		return $SMF_EXIT_ERR_FATAL
	fi

	if [ "$net_install_route" != "" ]; then
		if [ $ipv6_interface == 1 ]; then
			details="-inet6 default"
		else
			details="default"
		fi
		ifp=`echo $net_install_name | /usr/bin/cut -f1 -d'/'`
		details="$details $net_install_route -ifp $ifp"
		cmd="$ROUTE add $details"
		$cmd
		cmd="$ROUTE get $details"
		$cmd
		if [ $? -ne 0 ]; then
			err=$?
			msg="Error creating default route:\n\"$cmd\""
			net_record_err "$msg" $err
			return $SMF_EXIT_ERR_FATAL
		fi
		rootdir=/etc/svc/volatile
		/usr/bin/mkdir -p $rootdir/etc/inet
		if [ $? -ne 0 ]; then
			err=$?
			msg="Error creating \"$rootdir/etc/inet\" directory"
			net_record_err "$msg" $err
			return $SMF_EXIT_ERR_FATAL
		fi
		cmd="$ROUTE -R $rootdir -p add $details"
		$cmd
		if [ $? -ne 0 ]; then
			err=$?
			msg="Error adding persistent default route:\n\"$cmd\""
			net_record_err "$msg" $err
			return $SMF_EXIT_ERR_FATAL
		fi
	fi

	return $SMF_EXIT_OK
}

net_process_v4_pg()
{
	net_install_name=""
	net_install_addrtype=""
	net_install_addr=""
	net_install_dhcpwait=""
	net_install_route=""

	#
	# Retrieve the mandatory interface name property value. If
	# the value is empty, then no interface is configured.
	#
	prop=`$SVCPROP -p $NET_V4IF/name $NET_INSTALL_FMRI`
	if [ $? -ne 0 -o "$prop" = "$NET_UNDEFINED_STRING_PROP" ]; then
		return $SMF_EXIT_OK
	fi
	net_install_name=$prop

	#
	# Retrieve the mandatory address type property value. The two
	# valid values are "static" and "dhcp".
	#
	prop=`$SVCPROP -p $NET_V4IF/address_type $NET_INSTALL_FMRI`
	if [ $? -ne 0 -o "$prop" = "$NET_UNDEFINED_STRING_PROP" ]; then
		msg="No \"address_type\" property defined in the "
		msg=$msg"\"$NET_V4IF\" property group"
		net_record_err "$msg" 0
		return $SMF_EXIT_ERR_CONFIG
	fi
	case $prop in
	static | dhcp)
		net_install_addrtype=$prop
		;;
	*)
		msg="Bad value, \"$prop\", defined for the \"address_type\" "
		msg=$msg"property in the \"$NET_V4IF\" property group"
		net_record_err "$msg" 0
		return $SMF_EXIT_ERR_CONFIG
		;;
	esac

	#
	# Retrieve the static address property value. The address property
	# only applies to static address type configurations. If not
	# configuring a static address, then the property should still have
	# its default value of 0.0.0.0/0.
	#
	prop=`$SVCPROP -p $NET_V4IF/static_address $NET_INSTALL_FMRI`
	if [ $? -eq 0 -a "$prop" != "$NET_UNDEFINED_STRING_PROP" ]; then
		if [ "$net_install_addrtype" = "dhcp" ]; then
			if [ "$prop" != "${NET_INADDR_ANY}/0" ]; then
				msg="Warning: static address ignored "
				msg=$msg"in the \"$NET_V4IF\ property group"
				net_record_err "$msg" 0
			fi
		else
			if [ "$prop" = "${NET_INADDR_ANY}/0" ]; then
				msg="Error: static address required in the "
				msg=$msg"\"$NET_V4IF\" property group"
				net_record_err "$msg" 0
				return $SMF_EXIT_ERR_CONFIG
			fi
			net_install_addr=$prop
		fi
	else
		if [ "$net_install_addrtype" = "static" ]; then
			msg="Error: static address required in the "
			msg=$msg"\"$NET_V4IF\" property group"
			net_record_err "$msg" 0
			return $SMF_EXIT_ERR_CONFIG
		fi
	fi

	#
	# Retrieve the optional DHCP wait property value.
	#
	prop=`$SVCPROP -p $NET_V4IF/dhcp_wait $NET_INSTALL_FMRI`
	if [ $? -eq 0 -a "$prop" != "$NET_UNDEFINED_STRING_PROP" ]; then
		if [ "$net_install_addrtype" != "dhcp" ]; then
			if [ "$prop" != "120" ]; then
				msg="Warning: DHCP wait value ignored in the "
				msg=$msg"\"$NET_V4IF\" property group"
				net_record_err "$msg" 0
			fi
		else
			net_install_dhcpwait=$prop
		fi
	fi

	#
	# Retrieve the optional default route property value.
	#
	prop=`$SVCPROP -p $NET_V4IF/default_route $NET_INSTALL_FMRI`
	if [ $? -eq 0 -a "$prop" != "$NET_UNDEFINED_STRING_PROP" ]; then
		if [ "$prop" != "$NET_INADDR_ANY" ]; then
			net_install_route=$prop
		fi
	fi

	net_configure_install_if 0

	return $?
}

net_process_v6_pg()
{
	net_install_name=""
	net_install_addrtype=""
	net_install_addr=""
	net_install_stateless=""
	net_install_stateful=""
	net_install_interface_id=""
	net_install_route=""

	#
	# Retrieve the mandatory interface name property value. If
	# the value is empty, then no interface is configured.
	#
	prop=`$SVCPROP -p $NET_V6IF/name $NET_INSTALL_FMRI`
	if [ $? -ne 0 -o "$prop" = "$NET_UNDEFINED_STRING_PROP" ]; then
		return $SMF_EXIT_OK
	fi
	net_install_name=$prop

	#
	# Retrieve the mandatory address type property value. The two
	# valid values are "static" and "addrconf".
	#
	prop=`$SVCPROP -p $NET_V6IF/address_type $NET_INSTALL_FMRI`
	if [ $? -ne 0 -o "$prop" = "$NET_UNDEFINED_STRING_PROP" ]; then
		msg="No \"address_type\" property defined in the "
		msg=$msg"\"$NET_V6IF\" property group"
		net_record_err "$msg" 0
		return $SMF_EXIT_ERR_CONFIG
	fi
	case $prop in
	static | addrconf)
		net_install_addrtype=$prop
		;;
	*)
		msg="Bad value \"$prop\" defined for \"address_type\""
		net_record_err "$msg" 0
		return $SMF_EXIT_ERR_CONFIG
		;;
	esac

	#
	# Retrieve the static address property value. The address property
	# only applies to static address type configurations. If not
	# configuring a static address, then the property should still have
	# its default value of ::0/0.
	#
	prop=`$SVCPROP -p $NET_V6IF/static_address $NET_INSTALL_FMRI`
	if [ $? -eq 0 -a "$prop" != "$NET_UNDEFINED_STRING_PROP" ]; then
		if [ "$net_install_addrtype" = "addrconf" ]; then
			if [ "$prop" != "${NET_IN6ADDR_ANY_INIT}/0" ]; then
				msg="Warning: static address ignored in the "
				msg=$msg"\"$NET_V6IF\" property group"
				net_record_err "$msg" 0
			fi
		else
			if [ "$prop" = "${NET_IN6ADDR_ANY_INIT}/0" ]; then
				msg="Error: static address required in the "
				msg=$msg"\"$NET_V6IF\" property group"
				net_record_err "$msg" 0
				return $SMF_EXIT_ERR_CONFIG
			fi
			net_install_addr=$prop
		fi
	else
		if [ "$net_install_addrtype" = "static" ]; then
			msg="Error: static address required in the "
			msg=$msg"\"$NET_V6IF\" property group"
			net_record_err "$msg" 0
			return $SMF_EXIT_ERR_CONFIG
		fi

	fi

	#
	# Retrieve the optional interface id property value. The
	# property only applies to addrconf address type configurations.
	# If configuring a static address, then the property should still
	# have its default value of ::0/0.
	#
	prop=`$SVCPROP -p $NET_V6IF/interface_id $NET_INSTALL_FMRI`
	if [ $? -eq 0 -a "$prop" != "$NET_UNDEFINED_STRING_PROP" ]; then
		if [ "$prop" != "${NET_IN6ADDR_ANY_INIT}/0" ]; then
			if [ "$net_install_addrtype" != "addrconf" ]; then
				msg="Warning: interface id value ignored in "
				msg=$msg"the \"$NET_V6IF\" property group"
				net_record_err "$msg" 0
			else
				net_install_interface_id=$prop
			fi
		fi
	fi

	#
	# Retrieve the optional stateless property value. The property
	# only applies to addrconf address type configurations. If
	# configuring a static address, then the property should still
	# have its default value of "yes".
	#
	prop=`$SVCPROP -p $NET_V6IF/stateless $NET_INSTALL_FMRI`
	if [ $? -eq 0 -a "$prop" != "$NET_UNDEFINED_STRING_PROP" ]; then
		case $prop in
		yes)
			net_install_stateless=$prop
			;;
		no)
			if [ "$net_install_addrtype" != "addrconf" ]; then
				msg="Warning: stateless value ignored in the "
				msg=$msg"\"$NET_V6IF\" property group"
				net_record_err "$msg" 0
			else
				net_install_stateless=$prop
			fi
			;;
		*)
			msg="Bad value \"$prop\" defined for the \"stateless\""
			msg=$msg" property in the \"$NET_V6IF\" property group"
			net_record_err "$msg" 0
			return $SMF_EXIT_ERR_CONFIG
		;;
		esac
	fi

	#
	# Retrieve the optional stateful property value. The property
	# only applies to addrconf address type configurations. If
	# configuring a static address, then the property should still
	# have its default value of "yes".
	#
	prop=`$SVCPROP -p $NET_V6IF/stateful $NET_INSTALL_FMRI`
	if [ $? -eq 0 -a "$prop" != "$NET_UNDEFINED_STRING_PROP" ]; then
		case $prop in
		yes)
			net_install_stateful=$prop
			;;
		no)
			if [ "$net_install_addrtype" != "addrconf" ]; then
				msg="Warning: stateless value ignored in the "
				msg=$msg"\"$NET_V6IF\" property group"
				net_record_err "$msg" 0
			else
				net_install_stateful=$prop
			fi
			;;
		*)
			msg="Bad value \"$prop\" defined for the \"stateless\""
			msg=$msg" property in the \"$NET_V6IF\" property group"
			net_record_err "$msg" 0
			return $SMF_EXIT_ERR_CONFIG
		;;
		esac
	fi

	#
	# Retrieve the optional default route property value.
	#
	prop=`$SVCPROP -p $NET_V6IF/default_route $NET_INSTALL_FMRI`
	if [ $? -eq 0 -a "$prop" != "$NET_UNDEFINED_STRING_PROP" ]; then
		if [ "$prop" != "$NET_IN6ADDR_ANY_INIT" ]; then
			net_install_route=$prop
		fi
	fi

	net_configure_install_if 1

	return $?
}

net_process_install()
{
	vout=`$SVCCFG -s $NET_INSTALL_FMRI validate 2>&1`
	if [ "$vout" != "" ]; then
		msg="Validation errors in $NET_INSTALL_FMRI:\n$vout"
		net_record_err "$msg" 0
		return $SMF_EXIT_ERR_CONFIG
	fi

	ecode=$SMF_EXIT_OK
	errs=0
	ifcnt=0
	for intf in $NET_V4IF $NET_V6IF
	do
		pg=`$SVCPROP -p $intf $NET_INSTALL_FMRI`
		if [ $? -eq 0 ]; then
			if service_is_enabled $NET_NWAM_FMRI; then
				msg="NWAM enabled. Install static "
				msg=$msg"configuration ignored."
				net_record_err "$msg" 0
				errs=`expr $errs + 1`
				ecode=$SMF_EXIT_ERR_CONFIG
			else
				if [ "$intf" == "$NET_V4IF" ]; then
					net_process_v4_pg
				else
					net_process_v6_pg
				fi
				if [ $? -ne $SMF_EXIT_OK ]; then
					#
				    	# Last error wins.
					#
					ecode=$?
					errs=`expr $errs + 1`
				else
					ifcnt=`expr $ifcnt + 1`
				fi
			fi
			$SVCCFG -s $NET_INSTALL_FMRI delpg $intf
			$SVCCFG -s $NET_INSTALL_FMRI refresh
		fi
	done

 	if [ $net_install_debug -eq 1 ]; then
		if [ $errs -ne 0 ]; then
			echo "$errs errors encountered" \
			    "configuring interfaces on behalf of install"
		fi

		if [ $ifcnt -ne 0 ]; then
			echo "$ifcnt interfaces configured on" \
			    "behalf of install"
		fi
	fi

	return $ecode
}

#
# The network/install service will be enabled by the install derived profile
# after the intial install. The service will disable itself after processing
# the install defined property values.
#
# When the non-global shared-IP stack zone boots, it tries to bring up this
# service as well. We just want to exit successfully.
#
if smf_is_nonglobalzone; then
	if [ `/sbin/zonename -t` = shared ]; then
		$SVCADM disable $NET_INSTALL_FMRI
		exit $SMF_EXIT_OK
	fi
fi

net_process_install || exit $?

$SVCADM disable $NET_INSTALL_FMRI
exit $SMF_EXIT_OK
